package org.dicr.util.jds.conn.gui;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.*;

import org.dicr.event.*;
import org.dicr.gui.*;
import org.dicr.gui.layout.*;
import org.dicr.util.jds.conn.*;

/***********************************************************************************************************************
 * @author Igor A Tarasov me@dicr.dn.ua
 * @version 030113
 **********************************************************************************************************************/
public class ConnectionsFactoryPanel extends JPanel implements ProgramEventGenerator, DicrDialogContent {
	private static final long serialVersionUID = 1L;

	ConnectionsFactory factory = null;

	ProgramEventMulticaster listeners = new ProgramEventMulticaster();

	/** Selection changed event */
	public static final int EVENT_SELECTION_CHANGED = 1;

	ProgramEventMulticaster contentListeners = new ProgramEventMulticaster();

	private JScrollPane scroll = new JScrollPane();

	ConnectionsList list = new ConnectionsList();

	private JPanel controlPanel = new JPanel();

	private JButton addButton = new JButton("Создать");

	private JButton delButton = new JButton("Удалить");

	private JButton editButton = new JButton("Свойства");

	private JButton defButton = new JButton("По умолчанию");

	/*******************************************************************************************************************
	 * Конструктор
	 * 
	 * @param theFactory connection factory
	 * @param selectedConnection selected connection
	 ******************************************************************************************************************/
	public ConnectionsFactoryPanel(ConnectionsFactory theFactory, ConnectionElement selectedConnection) {
		try {
			jbInit(theFactory, selectedConnection);
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Конструктор
	 * 
	 * @param theFactory connection factory
	 ******************************************************************************************************************/
	public ConnectionsFactoryPanel(ConnectionsFactory theFactory) {
		try {
			jbInit(theFactory, null);
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Конструктор
	 * 
	 * @param selectedConnection selected connection
	 ******************************************************************************************************************/
	public ConnectionsFactoryPanel(ConnectionElement selectedConnection) {
		try {
			jbInit(null, selectedConnection);
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		}
	}

	/*******************************************************************************************************************
	 * Конструктор
	 ******************************************************************************************************************/
	public ConnectionsFactoryPanel() {
		this(null, null);
	}

	/*******************************************************************************************************************
	 * Инициализация
	 ******************************************************************************************************************/
	private void jbInit(ConnectionsFactory theFactory, ConnectionElement selectedConnection) throws Exception {
		this.setLayout(new BorderLayout(10, 0));
		this.add(this.scroll, BorderLayout.CENTER);
		this.add(this.controlPanel, BorderLayout.EAST);
		this.scroll.setViewportView(this.list);
		this.scroll.setPreferredSize(new Dimension(300, 300));
		this.scroll.setBorder(BorderFactory.createEtchedBorder());
		this.list.setAutoscrolls(true);
		ListListener listListener = new ListListener();
		this.list.getSelectionModel().addListSelectionListener(listListener);
		this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.list.setToolTipText("Список соединений");
		this.list.setVisibleRowCount(15);
		this.controlPanel.setLayout(new PnutsLayout(1, 2, 2));
		this.controlPanel.add(this.addButton, "halign=fill");
		this.controlPanel.add(this.delButton, "halign=fill");
		this.controlPanel.add(this.editButton, "halign=fill");
		this.controlPanel.add(this.defButton, "halign=fill");
		this.controlPanel.setBorder(BorderFactory.createEtchedBorder());
		this.addButton.setAction(new AddButtonAction());
		this.delButton.setAction(new DelButtonAction());
		this.editButton.setAction(new EditButtonAction());
		this.defButton.setAction(new DefButtonAction());
		updateControls();
		ConnectionsFactory cfactory = theFactory != null ? theFactory : new ConnectionsFactory();
		setFactory(cfactory);
		setSelectedConnection(selectedConnection != null ? selectedConnection : cfactory.getDefaultConnection());
	}

	/*******************************************************************************************************************
	 * Установка менеджера соединений
	 * 
	 * @param theFactory connection factory
	 ******************************************************************************************************************/
	public void setFactory(ConnectionsFactory theFactory) {
		if (this.factory != theFactory) try {
			this.factory = theFactory;
			this.list.setFactory(theFactory);
			if (theFactory != null) this.list.setSelectedValue(theFactory.getDefaultConnection(), true);
		} catch (Exception ex) {
			DicrExceptionHandler.handleException(ex, this);
		} finally {
			updateControls();
		}
	}

	/*******************************************************************************************************************
	 * Возвращает менеджер соединений
	 * 
	 * @return connection factory
	 ******************************************************************************************************************/
	public ConnectionsFactory getFactory() {
		return this.factory;
	}

	/*******************************************************************************************************************
	 * Обновление состояния кнопок
	 ******************************************************************************************************************/
	protected void updateControls() {
		if (this.factory == null) {
			this.addButton.setEnabled(false);
			this.delButton.setEnabled(false);
			this.editButton.setEnabled(false);
			this.defButton.setEnabled(false);
		} else {
			this.addButton.setEnabled(true);
			boolean sel = !this.list.isSelectionEmpty();
			this.delButton.setEnabled(sel);
			this.editButton.setEnabled(sel);
			this.defButton.setEnabled(sel);
		}
	}

	/*******************************************************************************************************************
	 * Возвращает выбранное значение
	 * 
	 * @return selected connection
	 ******************************************************************************************************************/
	public ConnectionElement getSelectedConnection() {
		return (ConnectionElement) this.list.getSelectedValue();
	}

	/*******************************************************************************************************************
	 * Устанавливает выбранное соединение
	 * 
	 * @param elem selected connection
	 ******************************************************************************************************************/
	public void setSelectedConnection(ConnectionElement elem) {
		this.list.setSelectedValue(elem, true);
	}

	/**
	 * @see org.dicr.event.ProgramEventGenerator#addProgramListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void addProgramListener(ProgramListener l) {
		this.listeners.addProgramListener(l);
	}

	/**
	 * @see org.dicr.event.ProgramEventGenerator#removeProgramListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void removeProgramListener(ProgramListener l) {
		this.listeners.removeProgramListener(l);
	}

	/**
	 * @see org.dicr.gui.DicrDialogContent#addContentListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void addContentListener(ProgramListener l) {
		this.contentListeners.addProgramListener(l);
	}

	/**
	 * @see org.dicr.gui.DicrDialogContent#removeContentListener(org.dicr.event.ProgramListener)
	 */
	@Override
    public void removeContentListener(ProgramListener l) {
		this.contentListeners.removeProgramListener(l);
	}

	/**
	 * @see org.dicr.gui.DicrDialogContent#shutdown()
	 */
	@Override
    public void shutdown() {
		this.setFactory(null);
	}

	/*******************************************************************************************************************
	 * Обработчик событий кнопки добавления
	 ******************************************************************************************************************/
	class AddButtonAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		/**
		 * Constructor
		 */
		public AddButtonAction() {
			putValue(SHORT_DESCRIPTION, "Создание нового соединения к базе данных");
			putValue(NAME, "Добавить");
		}

		/**
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
        public void actionPerformed(ActionEvent e) {
			if (ConnectionsFactoryPanel.this.factory != null) try {
				ConnectionElement elem = new ConnectionElement();
				elem.setName("Новое соединение");
				ConnectionsFactoryPanel.this.factory.setConnection(elem);
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this, true);
			}
		}
	}

	/*******************************************************************************************************************
	 * Обработчик событий кнопки добавления
	 ******************************************************************************************************************/
	class DelButtonAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		/**
		 * Constructor
		 */
		public DelButtonAction() {
			putValue(SHORT_DESCRIPTION, "Удалить соединение к базе данных");
			putValue(NAME, "Удалить");
		}

		/**
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
        public void actionPerformed(ActionEvent e) {
			if (ConnectionsFactoryPanel.this.factory != null) try {
				ConnectionElement elem = (ConnectionElement) ConnectionsFactoryPanel.this.list.getSelectedValue();
				if (elem == null) return;
				if (JOptionPane.showConfirmDialog(ConnectionsFactoryPanel.this, "Удалить соединение '" + elem.getName()
				        + "' ?", "Удаление соединения", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION) return;
				ConnectionsFactoryPanel.this.factory.removeConnection(elem.getID());
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this, true);
			}
		}
	}

	/*******************************************************************************************************************
	 * ######################################################################### Обработчик событий кнопки добавления
	 * #########################################################################
	 ******************************************************************************************************************/
	class EditButtonAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		/**
		 * Constructor
		 */
		public EditButtonAction() {
			putValue(SHORT_DESCRIPTION, "Изменить свойства соединения");
			putValue(NAME, "Свойства");
		}

		/**
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
        public void actionPerformed(ActionEvent e) {
			if (ConnectionsFactoryPanel.this.factory != null) try {
				ConnectionElement elem = (ConnectionElement) ConnectionsFactoryPanel.this.list.getSelectedValue();
				if (elem == null) return;

				elem = new ConnectionElementPanel(elem).showEditDialog(ConnectionsFactoryPanel.this);
				if (elem != null) ConnectionsFactoryPanel.this.factory.setConnection(elem);
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this);
			}
		}
	}

	/*******************************************************************************************************************
	 * ######################################################################### Обработчик событий кнопки добавления
	 * #########################################################################
	 ******************************************************************************************************************/
	class DefButtonAction extends AbstractAction {
		private static final long serialVersionUID = 1L;

		/**
		 * Constructor
		 */
		public DefButtonAction() {
			putValue(SHORT_DESCRIPTION, "Использовать данное соединение по умолчанию как основное");
			putValue(NAME, "По умолчанию");
		}

		/**
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		@Override
        public void actionPerformed(ActionEvent e) {
			if (ConnectionsFactoryPanel.this.factory != null) try {
				ConnectionElement elem = (ConnectionElement) ConnectionsFactoryPanel.this.list.getSelectedValue();
				if (elem == null) return;
				ConnectionsFactoryPanel.this.factory.setDefaultConnectionID(elem.getID());
			} catch (Exception ex) {
				DicrExceptionHandler.handleException(ex, this, true);
			}
		}
	}

	/*******************************************************************************************************************
	 * ######################################################################### Слушатель списка
	 * #########################################################################
	 ******************************************************************************************************************/
	class ListListener implements ListSelectionListener {
		/**
		 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
		 */
		@Override
        public void valueChanged(ListSelectionEvent e) {
			if (!e.getValueIsAdjusting()) updateControls();

			ConnectionElement conn = getSelectedConnection();
			ConnectionsFactoryPanel.this.listeners.fireProgramEvent(new ProgramEvent(ConnectionsFactoryPanel.this,
			        EVENT_SELECTION_CHANGED, conn));
			ConnectionsFactoryPanel.this.contentListeners.fireProgramEvent(new ProgramEvent(
			        ConnectionsFactoryPanel.this, DicrDialogContent.EVENT_ACCEPT_ALLOW_CHANGED, Boolean.valueOf(
			                conn != null)));
		}
	}

	/*******************************************************************************************************************
	 * Создает диалог менеджера
	 * 
	 * @param parent parent component
	 * @param theFactory connection factory
	 * @param selectedConnection selected connection
	 * @return crated dialog
	 ******************************************************************************************************************/
	public DicrDialog createManagerDialog(Component parent, ConnectionsFactory theFactory, ConnectionElement selectedConnection) {
		if (theFactory != null) this.setFactory(theFactory);
		if (selectedConnection != null) this.setSelectedConnection(selectedConnection);
		return new DicrDialog(parent, "Менеджер соединений", DicrDialog.DIALOG_SIMPLE, this);
	}

	/*******************************************************************************************************************
	 * Показывает диалог менеджера соединений
	 * 
	 * @param parent parent component
	 * @param theFactory connection factory
	 * @param selectedConnection selected connection
	 ******************************************************************************************************************/
	public void showManagerDialog(Component parent, ConnectionsFactory theFactory, ConnectionElement selectedConnection) {
		DicrDialog dialog = createManagerDialog(parent, theFactory, selectedConnection);
		dialog.setVisible(true);
	}

	/*******************************************************************************************************************
	 * Показывает диалог менеджера соединений
	 * 
	 * @param parent parent component
	 ******************************************************************************************************************/
	public void showManagerDialog(Component parent) {
		showManagerDialog(parent, null, null);
	}

	/*******************************************************************************************************************
	 * Создает диалог выбора соединений
	 * 
	 * @param parent parent componene
	 * @param theFactory connection factory
	 * @param selectedConnection selected connection
	 * @return created dialog
	 ******************************************************************************************************************/
	public DicrDialog createConnectionSelectDialog(Component parent, ConnectionsFactory theFactory, ConnectionElement selectedConnection) {
		if (theFactory != null) this.setFactory(theFactory);
		if (selectedConnection != null) this.setSelectedConnection(selectedConnection);
		return new DicrDialog(parent, "Выберите соединение", DicrDialog.DIALOG_YES_NO, this);
	}

	/*******************************************************************************************************************
	 * Показывает диалогое окно выбора соединения
	 * 
	 * @param parent parent component
	 * @param theFactory connection factory
	 * @param selectedConnection selected connection
	 * @return created dialog
	 ******************************************************************************************************************/
	public ConnectionElement showConnectionSelectDialog(Component parent, ConnectionsFactory theFactory, ConnectionElement selectedConnection) {
		DicrDialog dialog = createConnectionSelectDialog(parent, theFactory, selectedConnection);
		dialog.setVisible(true);
		ConnectionElement elem = dialog.isAccepted() ? getSelectedConnection() : null;
		this.shutdown();
		return elem;
	}

	/*******************************************************************************************************************
	 * Показывает диалогое окно выбора соединения
	 * 
	 * @param parent parent component
	 * @return selected connection
	 ******************************************************************************************************************/
	public ConnectionElement showConnectionSelectDialog(Component parent) {
		return showConnectionSelectDialog(parent, null, null);
	}
}
